﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;

using System.Diagnostics;

namespace DDOLayoutEditor
{
    internal static class FileParser
    {
        public static void Save(string path, List<Group> groups)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(path);

            foreach (Group group in groups)
            {
                if (group.Items != null)
                {
                    foreach (ItemControl item in group.Items)
                    {
                        bool hide = false;

                        // Probably a more WPF way of doing this, but whatever.  If it is invisible it may not have had its layout updated
                        // so we are going to show it, update its layout and then hide it again.
                        if (item.IsVisible == false)
                        {
                            item.Visibility = Visibility.Visible;
                            item.UpdateLayout();

                            hide = true;
                        }

                        Rect rect = item.CalculateLayout();

                        //Debug.Assert(item.Rect.Width == rect.Width, "Width doesn't match");
                        //Debug.Assert(item.Rect.Height == rect.Height, "Height doesn't match");
                        //Debug.Assert(item.Rect.X == rect.X, "X doesn't match");
                        //Debug.Assert(item.Rect.Y == rect.Y, "Y doesn't match");

                        XmlNode node = doc.SelectSingleNode(String.Format("/UI/Layouts/Layout[@ID='{0}']/Element[@ID='{1}']", item.LayoutID, item.ID));
                        if (node != null)
                        {
                            node.Attributes["Height"].Value = rect.Height.ToString("0.000000");
                            node.Attributes["Width"].Value = rect.Width.ToString("0.000000");

                            node.Attributes["X"].Value = rect.X.ToString("0.000000");
                            node.Attributes["Y"].Value = rect.Y.ToString("0.000000");
                        }

                        if (hide)
                            item.Visibility = Visibility.Hidden;
                    }
                }
            }

            doc.Save(path);
        }

        private static void SpecialSort(Group group, Func<ItemControl, int> sorter)
        {
            Dictionary<int, List<ItemControl>> dict = new Dictionary<int, List<ItemControl>>();

            foreach (ItemControl item in group.Items)
            {
                int index = sorter(item);

                if (dict.ContainsKey(index))
                    dict[index].Add(item);
                else
                    dict[index] = new List<ItemControl> { item };
            }

            group.Items.Clear();
            foreach (var item in dict.OrderBy(i => i.Key))
                group.Items.AddRange(item.Value);
        }

        public static List<Group> Load(string path)
        {
            List<Group> groups = new List<Group>();
            XmlDocument doc = new XmlDocument();

            doc.Load(path);

            foreach (SettingGroup settingGroup in Settings.Groups)
            {
                Group group = new Group();

                group.DisplayName = settingGroup.Name;

                foreach (SettingItem settingItem in settingGroup.ItemSettings)
                {
                    XmlNode layoutNode = doc.SelectSingleNode(String.Format("/UI/Layouts/Layout[@ID='{0}']", settingItem.LayoutID));
                    XmlNodeList itemNodes;

                    if (settingItem.ID == "*")
                        itemNodes = layoutNode.SelectNodes("Element");
                    else
                        itemNodes = layoutNode.SelectNodes(String.Format("Element[@ID='{0}']", settingItem.ID));

                    foreach (XmlNode itemNode in itemNodes)
                    {
                        #region Parse the Child Element

                        ItemControl item = new ItemControl();

                        item.ID = itemNode.Attributes["ID"].Value;
                        item.LayoutID = itemNode.ParentNode.Attributes["ID"].Value;
                        item.IsResizable = settingItem.CanResize;

                        item.BackgroundColor = settingItem.BackgroundColor;
                        item.TextColor = settingItem.TextColor;

                        item.RequestedMinWidthRatio = settingItem.MinSize.Width;
                        item.RequestedMinHeightRatio = settingItem.MinSize.Height;

                        item.RequestedTopRatio = double.Parse(itemNode.Attributes["Y"].Value);
                        item.RequestedLeftRatio = double.Parse(itemNode.Attributes["X"].Value);

                        item.RequestedHeightRatio = double.Parse(itemNode.Attributes["Height"].Value);
                        item.RequestedWidthRatio = double.Parse(itemNode.Attributes["Width"].Value);
                        
                        #region Create the Display Name

                        if (String.IsNullOrWhiteSpace(settingItem.Name))
                        {
                            string displayName = item.ID;

                            if (item.ID.StartsWith("UndockedShortcut"))
                            {
                                // Let's make this a little prettier for the user
                                // UndockedShortcut2_Vertical_MarkerList
                                displayName = "Shortcut " + (int.Parse(displayName.Split('_')[0].Replace("UndockedShortcut", "")) + 1);
                            }
                            else
                            {
                                // Various names
                                // FellowshipDisplay, ArenaScoring_SummaryPanel, Guild_Bank_Field, PendingChallengeButton
                                displayName = displayName.Replace("_", " ");
                                displayName = Regex.Replace(Regex.Replace(displayName, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2");
                                displayName = Regex.Replace(displayName, @"[ ]{2,}", @" ", RegexOptions.None);
                            }

                            item.DisplayName = displayName;
                        }
                        else
                        {
                            item.DisplayName = settingItem.Name;
                        }

                        item.Visibility = Visibility.Collapsed;

                        #endregion

                        group.Items.Add(item);

                        #endregion
                    }

                    #region Item Sorting
                    
                    if (group.Items.Count > 0)
                    {
                        // TODO: Maybe drive this off a different attribute and not display name?
                        if (group.DisplayName == "Chat")
                        {
                            #region Special Sort

                            SpecialSort(group, f => {
                                if (f.ID.StartsWith("ChatDisplay"))
                                {
                                    int index = 0;
                                    int.TryParse(f.ID.Replace("ChatDisplay", ""), out index);

                                    return index;
                                }

                                return -1;
                            });

                            #endregion
                        }
                        else if (group.DisplayName == "Shortcuts")
                        {
                            #region Special Sort

                            SpecialSort(group, f => {
                                if (f.ID == "ShortcutsBar")
                                    return int.MinValue;

                                if (f.ID.StartsWith("UndockedShortcut"))
                                {
                                    int index = 0;
                                    int.TryParse(f.ID.Split('_')[0].Replace("UndockedShortcut", ""), out index);

                                    return index;
                                }

                                return -1;
                            });

                            #endregion
                        }
                        else
                        {
                            #region Just sort on DisplayName

                            var sorted = group.Items.OrderBy(i => i.DisplayName).ToList();

                            group.Items.Clear();
                            group.Items.AddRange(sorted);

                            #endregion
                        }
                    }

                    #endregion
                }

                if (group.Items.Count > 0)
                    groups.Add(group);
                
            }

            return groups;
        }
    }
}
